/*
 * Ina226App.cpp
 *
 *  Created on: 2021-07-25
 *      Author: vicent-PC
 */
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/ledc.h"
#include "esp_err.h"


#include "PwmCtl.h"
#include "../c3log.h"

#define LEDC_HS_TIMER          LEDC_TIMER_0
#define LEDC_HS_MODE           LEDC_LOW_SPEED_MODE
#if SOC_LEDC_SUPPORT_HS_MODE
	#define LEDC_HS_MODE           LEDC_HIGH_SPEED_MODE
#endif

#define LEDC_LS_TIMER          LEDC_TIMER_1
#define LEDC_LS_MODE           LEDC_LOW_SPEED_MODE
#define LEDC_LS_CH2_GPIO       (4)
#define LEDC_LS_CH2_CHANNEL    LEDC_CHANNEL_2
#define LEDC_LS_CH3_GPIO       (5)
#define LEDC_LS_CH3_CHANNEL    LEDC_CHANNEL_3

#define LEDC_TEST_CH_NUM       (1)
#define LEDC_TEST_DUTY         (2000)
#define LEDC_TEST_FADE_TIME    (1000)


#define LEDC_PWM_OUT_GPIO       (8)


/*
    * Prepare individual configuration
    * for each channel of LED Controller
    * by selecting:
    * - controller's channel number
    * - output duty cycle, set initially to 0
    * - GPIO number where LED is connected to
    * - speed mode, either high or low
    * - timer servicing selected channel
    *   Note: if different channels use one timer,
    *         then frequency and bit_num of these channels
    *         will be the same
    */
ledc_channel_config_t g_ledc_channel[LEDC_TEST_CH_NUM] = {
    {
        .gpio_num   = LEDC_PWM_OUT_GPIO,
        .speed_mode = LEDC_LS_MODE,
        .channel    = LEDC_LS_CH2_CHANNEL,
        .intr_type = LEDC_INTR_DISABLE,
        .timer_sel  = LEDC_LS_TIMER,
        .duty       = 0, //resolution is 2**13
        .hpoint     = 0,
    },
};

PwmCtl::PwmCtl(){

}

PwmCtl::~PwmCtl(){

}

int PwmCtl::init(int gpio = LEDC_PWM_OUT_GPIO) {
    int ch;
    /*
     * Prepare and set configuration of timers
     * that will be used by LED Controller
     */
    ledc_timer_config_t ledc_timer = {
        .speed_mode = LEDC_LS_MODE,           // timer mode
        .duty_resolution = LEDC_TIMER_13_BIT, // resolution of PWM duty
        .timer_num = LEDC_LS_TIMER,            // timer index
        .freq_hz = 10,                      // frequency of PWM signal
        .clk_cfg = LEDC_AUTO_CLK,              // Auto select the source clock
    };

    // Set configuration of timer0 for high speed channels
    ledc_timer_config(&ledc_timer);

    #if 0
    // Prepare and set configuration of timer1 for low speed channels
    ledc_timer.speed_mode = LEDC_LS_MODE;
    ledc_timer.timer_num = LEDC_LS_TIMER;
    ledc_timer_config(&ledc_timer);
    #endif

    // Set LED Controller with previously prepared configuration
    for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
        g_ledc_channel[ch].gpio_num = gpio;
        ledc_channel_config(&g_ledc_channel[ch]);
    }

    // Initialize fade service.
    ledc_fade_func_install(0);
    return 0;
}

int PwmCtl::run() {
    int ch = 0;
    printf("1. LEDC fade up to duty = %d\n", LEDC_TEST_DUTY);
    for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
        ledc_set_fade_with_time(g_ledc_channel[ch].speed_mode,
                g_ledc_channel[ch].channel, LEDC_TEST_DUTY, LEDC_TEST_FADE_TIME);
        ledc_fade_start(g_ledc_channel[ch].speed_mode,
                g_ledc_channel[ch].channel, LEDC_FADE_NO_WAIT);
    }
    vTaskDelay(LEDC_TEST_FADE_TIME / portTICK_PERIOD_MS);

    printf("2. LEDC fade down to duty = 0\n");
    for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
        ledc_set_fade_with_time(g_ledc_channel[ch].speed_mode,
                g_ledc_channel[ch].channel, 0, LEDC_TEST_FADE_TIME);
        ledc_fade_start(g_ledc_channel[ch].speed_mode,
                g_ledc_channel[ch].channel, LEDC_FADE_NO_WAIT);
    }
    vTaskDelay(LEDC_TEST_FADE_TIME / portTICK_PERIOD_MS);

    printf("3. LEDC set duty = %d without fade\n", LEDC_TEST_DUTY);
    for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
        ledc_set_duty(g_ledc_channel[ch].speed_mode, g_ledc_channel[ch].channel, LEDC_TEST_DUTY);
        ledc_update_duty(g_ledc_channel[ch].speed_mode, g_ledc_channel[ch].channel);
    }
    vTaskDelay(1000 / portTICK_PERIOD_MS);

    printf("4. LEDC set duty = 0 without fade\n");
    for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
        ledc_set_duty(g_ledc_channel[ch].speed_mode, g_ledc_channel[ch].channel, 0);
        ledc_update_duty(g_ledc_channel[ch].speed_mode, g_ledc_channel[ch].channel);
    }
    vTaskDelay(1000 / portTICK_PERIOD_MS);
    return 0;
}

int PwmCtl::runOn() {
    int ch = 0;
    //printf("3. LEDC set duty = %d without fade\n", LEDC_TEST_DUTY);
    for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
        ledc_set_duty(g_ledc_channel[ch].speed_mode, g_ledc_channel[ch].channel, 8192/1000);
        ledc_update_duty(g_ledc_channel[ch].speed_mode, g_ledc_channel[ch].channel);
    }
    return 0;
}

int PwmCtl::runOff() {
    int ch = 0;
    //printf("4. LEDC set duty = 0 without fade\n");
    for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
        ledc_set_duty(g_ledc_channel[ch].speed_mode, g_ledc_channel[ch].channel, 8192/1000);
        ledc_update_duty(g_ledc_channel[ch].speed_mode, g_ledc_channel[ch].channel);
    }
    return 0;
}

// percent (0-100)
float PwmCtl::setDuty(float percent = 100.0) {
    int ch = 0;
    if (percent < 0) percent = 0;
    if (percent > 100) percent = 100;
    //printf("4. LEDC set duty = 0 without fade\n");
    for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
        ledc_set_duty(g_ledc_channel[ch].speed_mode, g_ledc_channel[ch].channel, (8192 * percent) / 100);
        ledc_update_duty(g_ledc_channel[ch].speed_mode, g_ledc_channel[ch].channel);
    }
    return percent;
}

// percent (0-1000)
float PwmCtl::setDuty1000(float percent = 1000.0) {
    int ch = 0;
    if (percent < 0) percent = 0;
    if (percent > 1000) percent = 1000;
    //printf("4. LEDC set duty = 0 without fade\n");
    for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
        ledc_set_duty(g_ledc_channel[ch].speed_mode, g_ledc_channel[ch].channel, (8192 * percent) / 1000);
        ledc_update_duty(g_ledc_channel[ch].speed_mode, g_ledc_channel[ch].channel);
    }
    return percent;
}

